use crate::dto::{
    match_ok,
    menu::{MenuTree, RoleMenuTree, SysMenuModifyPayload, SysMenuPage, SysMenuPagePayload},
    res_json_custom, res_json_ok, Res, ResObj,
};
use crate::service::menu_service;
use hypers::prelude::*;

pub struct Menu;

#[openapi(prefix = "/system", name = "/menu", tag = "菜单")]
impl Menu {
    /// 菜单列表
    #[get(
        "/list",
        parameter(
            SysMenuPagePayload
        ),
        response(
            (status = 200,body=ResObj<Vec<SysMenuPage>>,description ="菜单列表")
        ),
    )]
    async fn get_menu_list(payload: SysMenuPagePayload) -> Res<Vec<SysMenuPage>> {
        match menu_service::get_menu_list(payload.menu_name.clone(), payload.status.clone()).await {
            Ok(v) => Ok(res_json_ok(Some(v))),
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }

    /// 添加菜单
    #[post(
        "/",
        response(
            (status = 200,body=ResObj<()>,description ="添加菜单")
        ),
    )]
    async fn add_menu(payload: Json<SysMenuModifyPayload>, req: &mut Request) -> Res<()> {
        let user_id = req.get::<i32>("userId").unwrap();
        match menu_service::add_menu(user_id, payload.0).await {
            Ok(v) => {
                if v {
                    Ok(res_json_ok(Some(())))
                } else {
                    Err(res_json_custom(400, "添加失败".to_owned()))
                }
            }
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }

    /// 修改菜单
    #[put(
        "/",
        response(
            (status = 200,body=ResObj<()>,description ="修改菜单")
        ),
    )]
    async fn put_edit_menu(payload: Json<SysMenuModifyPayload>, req: &mut Request) -> Res<()> {
        let user_id = req.get::<i32>("userId").unwrap();
        match menu_service::edit_menu(user_id, payload.0).await {
            Ok(v) => {
                if v {
                    Ok(res_json_ok(Some(())))
                } else {
                    Err(res_json_custom(400, "修改失败".to_owned()))
                }
            }
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }

    /// 删除菜单
    #[delete(
        "/:id",
        response(
            (status = 200,body=ResObj<()>,description ="删除菜单")
        ),
    )]
    async fn del_menu_by_id(id: Path<i64>) -> Res<()> {
        match menu_service::del_menu_by_id(id.0).await {
            Ok(v) => {
                if v {
                    Ok(res_json_ok(Some(())))
                } else {
                    Err(res_json_custom(400, "删除失败".to_owned()))
                }
            }
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }

    /// 菜单详情
    #[get(
        "/:id",
        response(
            (status = 200,body=ResObj<SysMenuPage>,description ="菜单详情")
        ),
    )]
    async fn get_menu_by_id(id: Path<i64>) -> Res<SysMenuPage> {
        match menu_service::get_menu_detail_by_id(id.0).await {
            Ok(v) => Ok(res_json_ok(v)),
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }

    /// 菜单树
    #[get(
        "/treeselect",
        response(
            (status = 200,body=ResObj<Vec<MenuTree>>,description ="菜单树")
        ),
    )]
    async fn get_menu_tree() -> Res<Vec<MenuTree>> {
        match_ok(menu_service::get_menu_tree().await)
    }

    /// 菜单树和根据用户获取已选菜单id
    #[get(
        "/roleMenuTreeselect/:id",
        response(
            (status = 200,body=ResObj<RoleMenuTree>,description ="菜单树和根据用户获取已选菜单id")
        ),
    )]
    async fn get_role_menu_tree_by_user_id(id: Path<i32>) -> Res<RoleMenuTree> {
        match menu_service::get_menu_tree().await {
            Ok(v1) => match menu_service::get_menu_id_by_role_id(id.0).await {
                Ok(v2) => {
                    let role_menu_tree = RoleMenuTree {
                        menus: v1,
                        checked_keys: v2,
                    };
                    Ok(res_json_ok(Some(role_menu_tree)))
                }
                Err(err) => Err(res_json_custom(400, err.to_string())),
            },
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }
}
